// Copyright (C) 1953-2022 NUDT
// Verilog module name - clock_domain_cross
// Version: V4.1.0.20221210
// Created:
//         by - fenglin 
////////////////////////////////////////////////////////////////////////////
// Description:
//         the internet clock field of the chip is switched to the external PHY clock field
//         send pkt data from gmii
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps

module clock_domain_cross #(parameter frame_gap = 5'd22)
(
       i_wr_clk,
       i_wr_rst_n,
       
       i_rd_clk,
       i_rd_rst_n,
              
       iv_data,
       i_data_wr,
       o_fifo_ready,
       
       o_fifo_overflow_pulse,
       
       ov_data,
       o_data_wr  
);

// I/O
// clk & rst
input                  i_wr_clk;                   //125Mhz
input                  i_wr_rst_n;

input                  i_rd_clk;
input                  i_rd_rst_n;
// receive pkt data from pkt_centralize_bufm_memory
input      [8:0]       iv_data   ;
input                  i_data_wr;
output                 o_fifo_ready;
// send pkt data from gmii     
output reg [8:0]       ov_data;
output reg             o_data_wr;

output reg             o_fifo_overflow_pulse;
//fifo
wire       [4:0]      wv_asfifo_wrusedw;
//ready generate
assign    o_fifo_ready = wv_asfifo_wrusedw < 5'd14 ? 1:0;
////////////////////////////////
/*
wire       [8:0]       wv_data_htd2fifo;
wire                   w_data_wr_htd2fifo;
head_and_tail_add head_and_tail_add_inst
(
    .i_clk           (i_wr_clk             ),
    .i_rst_n         (i_wr_rst_n           ),

    .i_data_wr       (i_data_wr         ),
    .iv_data         (iv_data           ),

    .ov_data         (wv_data_htd2fifo  ),
    .o_data_wr       (w_data_wr_htd2fifo)
);
*/
////////////////////////////////////////
//        read data from fifo         //
////////////////////////////////////////
wire       [8:0]       wv_rd_data;
reg                    w_rd;

reg        [4:0]       rv_frame_gap_cnt;
wire       [4:0]       wv_asfifo_rdusedw;
reg        [2:0]       ccd_state;  
localparam             IDLE_S                 = 3'd0,
                       WAIT1_S                = 3'd1,
                       WAIT2_S                = 3'd2,
                       OUTPUT_1ST_DATA_S      = 3'd3,
                       OUTPUT_DATAS_S         = 3'd4,
                       CONTROL_GAP_S          = 3'd5;
always @(posedge i_rd_clk or negedge i_rd_rst_n) begin
    if(i_rd_rst_n == 1'b0)begin
        ov_data          <= 8'h0;
        o_data_wr        <= 1'b0;
        rv_frame_gap_cnt <= 5'b0;
        w_rd             <= 1'b0;
        ccd_state        <= IDLE_S;
    end
    else begin
        case(ccd_state)
            IDLE_S:begin
                if(wv_asfifo_rdusedw >= 5'd4)begin
                    w_rd             <= 1'b1;
                    ov_data          <= 8'd0;
                    o_data_wr        <= 1'b0;
                    rv_frame_gap_cnt <= 5'b0;
                    ccd_state       <= OUTPUT_1ST_DATA_S;
                end
                else begin
                    w_rd             <= 1'b0;
                    ov_data          <= 8'd0;
                    o_data_wr        <= 1'b0;
                    rv_frame_gap_cnt <= 5'b0;
                    ccd_state        <= IDLE_S;
                end
            end          
            OUTPUT_1ST_DATA_S:begin
                w_rd              <= 1'b1;
                ov_data           <= wv_rd_data;
                o_data_wr         <= 1'b1;
                rv_frame_gap_cnt  <= 5'b0;
                ccd_state         <= OUTPUT_DATAS_S;            
            end
            OUTPUT_DATAS_S:begin
                ov_data      <= wv_rd_data;
                o_data_wr    <= 1'b1;
                rv_frame_gap_cnt  <= 5'b0;
                if(wv_rd_data[8] == 1'b1)begin//last byte data.
                    w_rd            <= 1'b0;
                    ccd_state       <= CONTROL_GAP_S;
                end
                else begin
                    w_rd            <= 1'b1;
                    ccd_state       <= OUTPUT_DATAS_S;
                end
            end
            CONTROL_GAP_S:begin
                w_rd         <= 1'b0;
                ov_data      <= 9'b0;
                o_data_wr    <= 1'b0;
                rv_frame_gap_cnt  <= rv_frame_gap_cnt + 1'b1;
                if(rv_frame_gap_cnt == frame_gap)begin
                    ccd_state       <= IDLE_S;
                end
                else begin
                    ccd_state       <= CONTROL_GAP_S;
                end            
            end
        endcase
    end
end
asyncfifo_w9d32_aclr_showahead asyncfifo_w9d32_aclr_showahead_inst
(
.data           (iv_data),    //  fifo_input.datain
.wrreq          (i_data_wr),   //            .wrreq
.rdreq          (w_rd),   //            .rdreq
.wrclk          (i_wr_clk),   //            .wrclk
.rdclk          (i_rd_clk),   //            .rdclk
.aclr           (!i_wr_rst_n),    //            .aclr
.q              (wv_rd_data),       // fifo_output.dataout
.rdusedw        (wv_asfifo_rdusedw), //            .rdusedw
.wrusedw        (wv_asfifo_wrusedw), //            .wrusedw
.rdempty        (), //            .rdempty
.wrfull         ()  //            .wrfull
	);
//xilinx ip
/*
asyncfifo_w9d32_aclr_showahead asyncfifo_w9d32_aclr_showahead_inst(
  .rst                (!i_wr_rst_n),
  .wr_clk             (i_wr_clk),
  .rd_clk             (i_rd_clk),
  .din                (iv_data  ),
  .wr_en              (i_data_wr),
  .rd_en              (w_rd),
  .dout               (wv_rd_data),
  .full               (),
  .empty              (),
  .rd_data_count      (wv_asfifo_rdusedw),
  .wr_data_count      (wv_asfifo_wrusedw),
  .wr_rst_busy        (),
  .rd_rst_busy        ()
);
*/
endmodule